home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / vbdatabs / vb_debug.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-17  |  14.9 KB  |  541 lines

  1. // ------------------------------- //
  2. // -------- Start of File -------- //
  3. // ------------------------------- //
  4. // ----------------------------------------------------------- // 
  5. // C++ Source Code File Name: vb_debug.cpp 
  6. // Compiler Used: MSVC40, DJGPP 2.7.2.1, GCC 2.7.2.1, HP CPP 10.24
  7. // Produced By: Doug Gaer 
  8. // File Creation Date: 02/04/1997  
  9. // Date Last Modified: 03/17/1999
  10. // Copyright (c) 1997 Douglas M. Gaer
  11. // ----------------------------------------------------------- // 
  12. // ------------- Program Description and Details ------------- // 
  13. // ----------------------------------------------------------- // 
  14. /*
  15. The VBD C++ classes are copyright (c) 1997, by Douglas M. Gaer.
  16. All those who put this code or its derivatives in a commercial
  17. product MUST mention this copyright in their documentation for
  18. users of the products in which this code or its derivative
  19. classes are used. Otherwise, you have the freedom to redistribute
  20. verbatim copies of this source code, adapt it to your specific
  21. needs, or improve the code and release your improvements to the
  22. public provided that the modified files carry prominent notices
  23. stating that you changed the files and the date of any change.
  24.  
  25. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
  26. THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE
  27. IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE,
  28. YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
  29. CORRECTION.
  30.  
  31. This program is used to display a detailed analysis of every
  32. variable data block allocated in a VBD file.
  33.  
  34. Changes:
  35. ================================================================
  36. 01/20/1998 - Rebuilds the VBD file static area data if the VBD
  37. header is still intact.
  38. Changed by: Doug Gaer
  39.  
  40. 03/09/1998 - Corrected "Checking the FreeSpace value" routine in
  41. AnalyzeHeader() function. In previous version the error value was
  42. incremented outside of the if(vb.CkWord != CheckWord) statement.
  43. Changed by: Doug Gaer
  44.  
  45. 06/10/1998 - Changed the Rebuild() function to write only normal
  46. variable blocks to the new file: if(vb.Status == NormalVB) 
  47. Changed by: Doug Gaer
  48. ================================================================
  49. */
  50. // ----------------------------------------------------------- // 
  51. #include <iostream.h>
  52. #include <iomanip.h>
  53. #include <string.h>
  54. #include "vbdfile.h"
  55. #include "vbdstats.h"
  56.  
  57. // Program name and version number
  58. const char *VersionNumber = "1031.101";
  59. const char *ProgramName = "vb_debug";
  60.  
  61. // Function prototypes for display menu
  62. void SkipToEol(istream &s);
  63. int Quit();
  64. void Menu(const VBDFilePtr &f);
  65. void pause();
  66. void Version();
  67.  
  68. // Function prototypes for VBD utilities 
  69. void FindVB(const VBDFilePtr &f, int verbose = 0, int walk = 0);
  70. void AnalyzeHeader(const VBDFilePtr &f);
  71. void DisplayStats(const VBDFilePtr &f);
  72. void Rebuild(const VBDFilePtr &f);
  73.  
  74. void DisplayStats(const VBDFilePtr &f)
  75. {
  76.   const char *FName = f->VBDFileName();
  77.   FileHeader fh;
  78.  
  79.   f->Read(&fh, sizeof(FileHeader), 0);
  80.   if(memcmp(fh.Signature, VBDFile::VBDSignature, 7)) { // Test file type
  81.     cout << endl;
  82.     cout << "VBD File Header is damaged or does not exist" << endl;
  83.     cout << endl;
  84.     return;
  85.   }
  86.  
  87.   cout << endl;
  88.   __SBYTE__ FileStatus = f->GetFileStatus(); // Get the current file status
  89.   cout << "----- VBD file statistics -----" << endl;
  90.   cout << endl;
  91.   VBDStats(f);
  92. }
  93.  
  94. void AnalyzeHeader(const VBDFilePtr &f)
  95. {
  96.   FileHeader fh;
  97.   VBHeader vb;
  98.   int errors = 0;
  99.   
  100.   f->Read(&fh, sizeof(FileHeader), 0);
  101.   cout << endl;
  102.   cout << "Analyzing VBD file header..." << endl;
  103.   cout << endl;
  104.  
  105.   cout << "Checking VBD signature..." << endl;
  106.   if (memcmp(fh.Signature, VBDFile::VBDSignature, 7)) { // Test file type
  107.     cout << endl;
  108.     cout << "VBD File Header is damaged or does not exist" <<endl;
  109.     cout << endl;
  110.     FindVB(f, 0);
  111.     return;
  112.   }
  113.   else if (memcmp(fh.Signature, VBDFile::VBDSignature, 8)) {
  114.     // Check revision letters
  115.     char revision[8];
  116.     revision[8] = 0; // Ensure null termination
  117.     char rev_letter;
  118.     cout << endl;
  119.     cout << "NOTE: The VBD file revision letters do not match." << endl;
  120.     memmove(revision, VBDFile::VBDSignature, 8);
  121.     rev_letter = revision[7];
  122.     if(rev_letter == 0)
  123.       cout << "Current VBD File Revision = NONE" << endl;
  124.     else
  125.       cout << "Current VBD File Revision = " << rev_letter << endl;
  126.     memmove(revision, fh.Signature, 8);
  127.     rev_letter = revision[7];
  128.     if(rev_letter == 0)
  129.       cout << "Current VBD File Revision = NONE" << endl;
  130.     else
  131.       cout << "The file reads: " << rev_letter << endl;
  132.     cout << "Backward compatibility rules will be enforced." << endl;
  133.     cout << endl;
  134.   }
  135.  
  136.   cout << "Checking for End of File errors..." << endl;
  137.   FAU StaticEOF = f->FileSize(f->VBDFileName());
  138.   if(StaticEOF > fh.EndOfFile) {
  139.     cout << endl;
  140.     cout << "End of file error in file: " << f->VBDFileName() << endl;
  141.     cout << "The actual length is longer then the allocated length!" << endl;
  142.     cout << endl;
  143.     errors++;
  144.   }
  145.  
  146.   cout << "Checking the HeapStart value..." << endl;
  147.   f->Read(&vb, sizeof(VBHeader), fh.HeapStart);
  148.   if (vb.CkWord != CheckWord) {
  149.     cout << endl;
  150.     cout << "Bad HeapStart value in file: " << f->VBDFileName() << endl;
  151.     cout << "No variable block found at file address: "
  152.      << fh.HeapStart << endl;
  153.     cout << endl;
  154.     errors++;
  155.   }
  156.  
  157.   cout << "Checking the FreeSpace value..." << endl;
  158.   if(fh.FreeSpace != 0) {
  159.     f->Read(&vb, sizeof(VBHeader), fh.FreeSpace);
  160.     if(vb.CkWord != CheckWord) {
  161.       cout << endl;
  162.       cout << "Bad FreeSpace value in file: " << f->VBDFileName() << endl;
  163.       cout << "No variable block found at file address: "
  164.        << fh.FreeSpace << endl;
  165.       cout << endl;
  166.       errors++;
  167.     }
  168.   }
  169.  
  170.   cout << "Checking the HighestVB value..." << endl;
  171.   f->Read(&vb, sizeof(VBHeader), fh.HighestVB);
  172.   if (vb.CkWord != CheckWord) {
  173.     cout << endl;
  174.     cout << "Bad HeapStart value in file: " << f->VBDFileName() << endl;
  175.     cout << "No variable block found at file address: "
  176.      << fh.HighestVB << endl;
  177.     cout << endl;
  178.     errors++;
  179.   }
  180.   
  181.   cout << "Checking the VBD version number..." << endl;
  182.   if(fh.Version != VBDFile::VBDVersion) {
  183.     cout << endl;
  184.     cout << "NOTE: The version numbers do not match." << endl;
  185.     cout << "Current VBD File Version = " << VBDFile::VBDVersion << endl;
  186.     cout << "The file reads: " << fh.Version << endl;
  187.     cout << "Backward compatibility rules will be enforced." << endl;
  188.     cout << endl;
  189.   }
  190.  
  191.   if(errors) {
  192.     cout << endl;
  193.     cout << "VBD file header has errors!" << endl;
  194.   }
  195.   else {
  196.     cout << endl;
  197.     cout << "VBD file header checks good." << endl;
  198.   }
  199.   cout << endl;
  200. }
  201.  
  202. void FindVB(const VBDFilePtr &f, int verbose, int walk)
  203. // Serach the file for all variable block.
  204. {
  205.   VBHeader vb;
  206.   int count = 0;
  207.   int badvb = 0;
  208.   
  209.   cout << endl;
  210.   cout << "Searching file for all variable blocks..." << endl;
  211.   
  212.   FAU StaticEOF = f->FileSize(f->VBDFileName());
  213.   FAU addr = f->VBSearch(0); // Search the entire file
  214.   
  215.   if(addr == 0) {
  216.     cout << endl;
  217.     cout << "No variable blocks found in file: "
  218.      << f->VBDFileName() << endl;
  219.     cout << endl;
  220.     return;
  221.   }
  222.   
  223.   while(1) { 
  224.     if(addr >= StaticEOF) break;
  225.     f->Read(&vb, sizeof(VBHeader), addr);
  226.  
  227.     if (vb.CkWord == CheckWord) {
  228.       count++; // Increment the variable block count
  229.       if(verbose) {
  230.     VBStats(f, (addr+sizeof(VBHeader)));
  231.     if(walk) {
  232.       char c;
  233.       cout << endl;
  234.       cout << "Press enter to continue or enter 'X' to exit >";
  235.       cin.clear();
  236.       cin.get(c);
  237.       switch(c) {
  238.         case 'x' : case 'X' :
  239.           cout << endl;
  240.           return;
  241.         default:
  242.           break;
  243.       }
  244.     }
  245.       }
  246.       addr = addr + vb.Length; // Goto the next variable block
  247.     }
  248.     else {
  249.       badvb++;
  250.       cout << endl;
  251.       cout << "Found bad variable block at address " << addr << endl;
  252.       cout << "Searching for next good variable block..." << endl;
  253.       addr = f->VBSearch(addr); // Search for the next good block
  254.       if(!addr) {
  255.     cout << "None found!" << endl;
  256.     cout << endl;
  257.     return;
  258.       }
  259.     }
  260.   }
  261.   cout << endl;
  262.   cout << "Found " << count << " good varible blocks." << endl;
  263.   if(badvb) cout << "Found " << badvb << " bad variable blocks." << endl;
  264.   cout << endl;
  265. }
  266.  
  267. void Rebuild(const VBDFilePtr &f)
  268. {
  269.   cout << endl;
  270.   cout << "Rebuilding damaged VBD file..." << endl;
  271.   cout << endl;
  272.  
  273.   char buf[255];
  274.   int retry = 3;
  275.   
  276.   while(1) { // Loop until a good file name is found
  277.     cout << "Enter new name of file to build >";
  278.     cin.getline(buf, sizeof(buf));
  279.     cout << endl;
  280.     if(!*buf) { // Return if nothing is entered
  281.       Menu(f);
  282.       return;
  283.     }
  284.     if(VBDFile::Exists(buf)) {
  285.       cout << "File already exists!" << endl << endl;
  286.        retry--;
  287.       if(!retry) {
  288.     Menu(f);
  289.     return;
  290.       }
  291.     }
  292.     else
  293.       break;
  294.   }
  295.  
  296.   FileHeader fh;
  297.   VBHeader vb;
  298.   int errors = 0;
  299.   
  300.   // Analyze the VBD file header to determine if the file has
  301.   // a pre-allocated static area
  302.   __LWORD__ static_area;
  303.   f->Read(&fh, sizeof(FileHeader), 0);
  304.  
  305.   // Check the VBD FileHeader's signature
  306.   if (memcmp(fh.Signature, VBDFile::VBDSignature, 8))
  307.     errors++; // Header is damaged and cannot be read
  308.  
  309.   if(!errors) { // Check the HeapStart value 
  310.     f->Read(&vb, sizeof(VBHeader), fh.HeapStart);
  311.     if (vb.CkWord != CheckWord)
  312.       errors++;
  313.   }
  314.  
  315.   // If no errors, calculate the the size of the static area
  316.   if(!errors) static_area = fh.HeapStart - sizeof(FileHeader);
  317.  
  318.   FAU StaticEOF = f->FileSize(f->VBDFileName());
  319.   FAU addr = f->VBSearch(0); // Search the entire file
  320.   
  321.   if(addr == 0) {
  322.     cout << endl;
  323.     cout << "No variable blocks found in file: "
  324.      << f->VBDFileName() << endl;
  325.     pause();
  326.     return;
  327.   }
  328.  
  329.   // Create the new file
  330.   VBDFilePtr NewFile(new VBDFile);
  331.   NewFile->Create(buf, static_area);
  332.  
  333.   int count = 0;
  334.   int badvb = 0;
  335.  
  336.   char *v;
  337.  
  338.   if(static_area) { // Write the static area data
  339.     v = new char[static_area];
  340.     f->Read(v, static_area, sizeof(FileHeader));
  341.     NewFile->Write(v, static_area, sizeof(FileHeader));
  342.     delete v;
  343.   }
  344.   
  345.   FAU ObjectLength;
  346.   UINT32 checksum;
  347.   char rev_letter = f->GetRevLetter();
  348.   
  349.   while(1) { 
  350.     if(addr >= StaticEOF) break;
  351.  
  352.     f->Read(&vb, sizeof(VBHeader), addr);
  353.     if(vb.CkWord == CheckWord) {
  354.       ObjectLength = f->ObjectLength(addr + sizeof(VBHeader));
  355.       v = new char[ObjectLength];
  356.       f->Read(v, ObjectLength);
  357.       if((__SBYTE__)vb.Status == NormalVB) {
  358.     count++; // Increment the variable block count
  359.     NewFile->Alloc(ObjectLength);
  360.     NewFile->Write(v, ObjectLength);
  361.     switch(rev_letter) {
  362.       case 'A':
  363.         checksum = calcCRC32(v, ObjectLength);
  364.         NewFile->Write(&checksum, sizeof(checksum));
  365.         break;
  366.  
  367.       default: // Default to versions prior to 1027 rev A
  368.         break;
  369.     }
  370.       }
  371.       delete v;
  372.       addr = addr + vb.Length; // Goto the next variable block
  373.     }
  374.     else {
  375.       badvb++;
  376.       addr = f->VBSearch(addr); // Search for the next good block
  377.       if(!addr) break; 
  378.     }
  379.   }
  380.   cout << endl;
  381.  
  382.   cout << "Wrote " << count << " good variable blocks to file: "
  383.        << NewFile->VBDFileName() << endl;
  384.  
  385.   if(static_area)
  386.     cout << "Wrote " << static_area << " bytes of Static area data."
  387.      << endl;
  388.  
  389.   if(badvb) 
  390.     cout << "Did not write " << badvb << " bad variables found in file: "
  391.      << f->VBDFileName() << endl;
  392.  
  393.   if(errors) {
  394.     cout << f->VBDFileName() << " file header is damaged!" << endl;
  395.     cout << "No header information was copied to "
  396.      << NewFile->VBDFileName() << endl;
  397.   }
  398.  
  399.   NewFile->Close();
  400.   cout << endl;
  401. }
  402.  
  403. void Menu(const VBDFilePtr &f)
  404. {
  405.   cout << endl;
  406.   cout << "Analyzing file: " << f->VBDFileName() << endl;
  407.   cout << "Enter the letter of your selection at the prompt." << endl;
  408.   cout << endl;
  409.   cout << "(A) - Analyze the VBD file header" << endl;
  410.   cout << "(D) - Dump every variable block" << endl;
  411.   cout << "(F) - Find every variable block in the file" << endl;
  412.   cout << "(H) - Displays this menu" << endl;
  413.   cout << "(Q) - Quit this program" << endl;
  414.   cout << "(R) - Rebuild a damaged VBD file" << endl;
  415.   cout << "(S) - Display VBD file statistics" << endl;
  416.   cout << "(W) - Walk through every variable block" << endl;
  417.   cout << endl;
  418. }
  419.  
  420. void SkipToEol(istream &s)
  421. // Used to clear istream
  422. {
  423.   char c;
  424.   s.clear();
  425.   while(s.get(c) && c != '\n') { ; }
  426. }
  427.  
  428. void pause()
  429. {
  430.   cout << endl;
  431.   cout << "Press enter to continue..." << endl;
  432.   cin.get();
  433. }
  434.  
  435. int Quit()
  436. {
  437.   cout << "Exiting..." << endl;
  438.   return 0;
  439. }
  440.  
  441. void Version()
  442. {
  443.   cout << endl;
  444.   cout << ProgramName << " version number: " << VersionNumber << endl;
  445.   cout << endl;
  446. }
  447.  
  448. int main(int argc, char **argv)
  449. {
  450.   // Display the program version information and exit the program
  451.   if(argc >= 2) {
  452.     if(strcmp(argv[1], "version") == 0) {
  453.       Version();
  454.       return 0;
  455.     }
  456.   }
  457.  
  458.   if(argc < 2) {
  459.     cerr << endl;
  460.     cerr << "VBD file debug utility version " << VersionNumber << endl;
  461.     cerr << "Usage: " << ProgramName << " infile.vbd" << endl;
  462.     cerr << "Usage: " << ProgramName << " infile.vbd (command)" << endl;
  463.     cerr << endl;
  464.     return 1;
  465.    }
  466.  
  467.   VBDFilePtr f(new VBDFile);   
  468.   const char *FName = argv[1];
  469.   if(!VBDFile::Exists(FName)) 
  470.     Error->SignalException(EHandler::NoFileExists);
  471.   else
  472.     f->BlindOpen(FName, VBDFile::READONLY);
  473.  
  474.   char key;
  475.   if(argc <= 2) Menu(f); // Not processing a command
  476.   int rv = 1;
  477.  
  478.   while(rv) {
  479.     if(argc > 2) { // Process a single command and exit the loop
  480.       key = *(argv[2]);
  481.       rv = 0;
  482.     }
  483.     else {
  484.       if (!cin) { // Input is in fail state
  485.     SkipToEol(cin); // Go to end of line
  486.     if (!cin) {  // Can't fix
  487.           cout << "Input stream is broken" << endl;
  488.           return 0;
  489.     }
  490.       }
  491.       cout << '>';
  492.       cin >> key;
  493.       if (!cin) continue; // Fix at top of loop
  494.     }
  495.     switch(key) {
  496.       case 'a' : case 'A' :
  497.     if(argc <= 2) SkipToEol(cin);
  498.     AnalyzeHeader(f);
  499.     break;
  500.       case 'f' : case 'F' :
  501.     if(argc <= 2) SkipToEol(cin);
  502.     FindVB(f);
  503.     break;
  504.       case 'd' : case 'D' :
  505.     if(argc <= 2) SkipToEol(cin);
  506.     FindVB(f, 1);
  507.     break;
  508.       case 'h' : case 'H' :
  509.     Menu(f);
  510.     break;
  511.       case '?' :
  512.     Menu(f);
  513.     break; 
  514.       case 'q' : case 'Q' :
  515.     rv = Quit();
  516.     break;
  517.       case 'r' : case 'R' :
  518.     if(argc <= 2) SkipToEol(cin);
  519.     Rebuild(f);
  520.     break;
  521.       case 's' : case 'S' :
  522.     if(argc <= 2) SkipToEol(cin);
  523.     DisplayStats(f);
  524.     break;
  525.       case 'w' : case 'W' :
  526.     if(argc <= 2) SkipToEol(cin);
  527.     FindVB(f, 1, 1);
  528.     break;
  529.       default:
  530.         cout << "Unrecognized command" << endl;
  531.     }
  532.   }
  533.  
  534.   return 0;
  535. }
  536. // ----------------------------------------------------------- //
  537. // ------------------------------- //
  538. // --------- End of File --------- //
  539. // ------------------------------- //
  540.  
  541.